/**
 * 
 */
package org.apollo.swing.commons;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 类反射工具
 * @author <a href="mailto:sealinglip@gmail.com">Sealinglip</a> 2007-3-2
 */
public class ClassUtils {
	private static Map<Class<?>, Class<?>> primitiveAndWrapperCls;
	static {
		primitiveAndWrapperCls = new HashMap<Class<?>, Class<?>>();
		primitiveAndWrapperCls.put(boolean.class, Boolean.class);
		primitiveAndWrapperCls.put(byte.class, Byte.class);
		primitiveAndWrapperCls.put(char.class, Character.class);
		primitiveAndWrapperCls.put(short.class, Short.class);
		primitiveAndWrapperCls.put(int.class, Integer.class);
		primitiveAndWrapperCls.put(long.class, Long.class);
		primitiveAndWrapperCls.put(float.class, Float.class);
		primitiveAndWrapperCls.put(double.class, Double.class);
	}

	/**
	 * 查找某个类中方法名和参数类型和指定参数匹配的公有方法（包含自身定义的和继承的公有方法）
	 * @param clazz
	 * @param methodName
	 * @param argTypes
	 * @return
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 */
	public static Method getPublicMethod(Class<?> clazz, String methodName, Class<?>... argTypes) throws SecurityException, NoSuchMethodException {
		try {
			return clazz.getMethod(methodName, argTypes);
		} catch (NoSuchMethodException e) {
			if (argTypes.length > 0) {
				Method m = findMethod(clazz.getMethods(), methodName, argTypes);
				if (m == null) {
					throw e;
				} else {
					return m;
				}
			} else {
				throw e;
			}
		}
	}

	/**
	 * 查找某个类中方法名和参数类型和指定参数匹配的方法（包含自身定义的和父类中定义的所有方法）
	 * @param clazz
	 * @param methodName
	 * @param argTypes
	 * @return
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 */
	public static Method getAnyMethod(Class<?> clazz, String methodName, Class<?>... argTypes) throws SecurityException, NoSuchMethodException {
		try {
			return clazz.getMethod(methodName, argTypes);
		} catch (NoSuchMethodException e) {
			// TODO 临时写法，下面的写法有严重的效率问题
			do {
				Method m = findMethod(clazz.getDeclaredMethods(), methodName, argTypes);
				if (m != null) {
					return m;
				}
				if (clazz.getSuperclass().equals(Object.class)) {
					throw e;
				} else {
					clazz = clazz.getSuperclass();
				}
			} while (true);
		}
	}

	/**
	 * 在方法数组中寻找匹配的方法
	 * @param methods
	 * @param methodName
	 * @param argTypes
	 * @return
	 */
	private static Method findMethod(Method[] methods, String methodName, Class<?>... argTypes) {
		for (Method method : methods) {
			if (!method.getName().equals(methodName)) {// 名称不匹配
				continue;
			}
			Class<?>[] parameterTypes = method.getParameterTypes();
			int argTypeLength = argTypes == null ? 0 : argTypes.length;
			if (parameterTypes.length != argTypeLength) {// 参数数目不匹配
				continue;
			}
			if (parameterTypes.length > 0) {
				for (int i = 0, in = parameterTypes.length; i < in; i++) {
					if (!compatible(parameterTypes[i], argTypes[i])) {
						continue;
					}
				}
			}
			return method;
		}
		return null;
	}

	/**
	 * 判断两个类型是否匹配
	 * @param parameterType
	 * @param argType
	 * @return
	 */
	private static boolean compatible(Class<?> parameterType, Class<?> argType) {
		if (argType == null) {// 参数为null的时候argType才会记录为null，所以这种情况只要参数类型不是原始类型即可
			return !parameterType.isPrimitive();
		} else {
			if (parameterType == argType || parameterType.isAssignableFrom(argType)) {
				return true;
			}
			// 处理基本类型和其包装类
			if (parameterType.isPrimitive()) {
				return argType.equals(primitiveAndWrapperCls.get(parameterType));
			}
			if (argType.isPrimitive()) {
				return parameterType.equals(primitiveAndWrapperCls.get(argType));
			}
		}
		return false;
	}
}